﻿// --- Copyright (c) 2010 Steven Hartgers ---
// Copyright (C) 2010 Steven Hartgers All rights are reserved.
// Author contact: fiinix00/at\gmail.com
// ------------------------------------------------------------------------
// This program is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more detail
//  
// You should have received a copy of the GNU General Public License 
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Hack.Numbers;
using Hack.Attributes;

namespace Hack
{
    public class ActionDisposable : IDisposable
    {
        Action action;

        public ActionDisposable(Action action)
        {
            this.action = action;
        }

        void IDisposable.Dispose()
        {
            action();
        }
    }
    /// <summary>
    /// 1D point, one to another
    /// </summary>
    /// <typeparam name="T">Type</typeparam>
    public class Range<T>
    {
        public T Start { get; set; }
        public T End { get; set; }
    }
    /// <summary>
    /// A Generic tree data structure
    /// </summary>
    /// <typeparam name="T">The type to store in the tree</typeparam>
    [OrginalAuthor(Author = "fullerjc", Url = "http://code.google.com/p/jonfuller/source/browse/trunk/code/CoreLib/src/CoreLib/Tree.cs?r=22")]
    public class Tree<T>
    {
        private readonly List<Tree<T>> _branches;
        private readonly T _value;

        /// <summary>
        /// Indexer into the branches of this tree (not recursive).
        /// </summary>
        /// <param name="key">The value of the branch to look for</param>
        /// <returns>The branch with the specified value (or null if not found)</returns>
        public Tree<T> this[T key]
        {
            get
            {
                return _branches.Find(branch => branch.Value.Equals(key));
            }
        }

        /// <summary>
        /// The branches of this tree
        /// </summary>
        public IEnumerable<Tree<T>> Branches
        {
            get { return _branches; }
        }

        /// <summary>
        /// The value for this branch/trunk of the tree
        /// </summary>
        public T Value
        {
            get { return _value; }
        }

        /// <summary>
        /// Creates the tree
        /// </summary>
        /// <param name="value">The value for this branch/trunk of the tree</param>
        public Tree(T value)
        {
            _value = value;
            _branches = new List<Tree<T>>();
        }

        /// <summary>
        /// Add a branch
        /// </summary>
        /// <param name="branch">The branch to add</param>
        public void AddBranch(Tree<T> branch)
        {
            _branches.Add(branch);
        }

        /// <summary>
        /// Add a branch
        /// </summary>
        /// <param name="branch">The object to create a new branch for</param>
        public void AddBranch(T branch)
        {
            AddBranch(new Tree<T>(branch));
        }

        /// <summary>
        /// Add a range of branches
        /// </summary>
        /// <param name="newBranches">The branches to add</param>
        public void AddBranches(IEnumerable<Tree<T>> newBranches)
        {
            _branches.AddRange(newBranches);
        }

        /// <summary>
        /// Add a range of branches
        /// </summary>
        /// <param name="newBranches">The objects to create new branhces for</param>
        public void AddBranches(IEnumerable<T> newBranches)
        {
            foreach (var branch in newBranches)
                AddBranch(branch);
        }

        /// <summary>
        /// Look recursively through the tree for something that causes the <paramref name="finder"/> to pass
        /// </summary>
        /// <param name="finder">The finder predicate</param>
        /// <returns>The found tree/branch, or null</returns>
        public Tree<T> FindRecursive(Func<T, bool> finder)
        {
            if (finder(Value))
            {
                return this;
            }
            foreach (var branch in _branches)
            {
                var found = branch.FindRecursive(finder);
                if (found != null)
                {
                    return found;
                }
            }
            return null;
        }

        /// <summary>
        /// Sorts, recursively
        /// </summary>
        /// <param name="comparison">The comparison used to sort.</param>
        public void Sort(Comparison<Tree<T>> comparison)
        {
            _branches.Sort(comparison);
            _branches.ForEach(branch => branch.Sort(comparison));
        }

        /// <summary>
        /// Provides a mechanism to recurse through the tree
        /// </summary>
        /// <param name="action">The action to yield to for each branch</param>
        public void ForEachRecursive(Action<Tree<T>> action)
        {
            ForEachRecursive((tree, ancestry) => action(tree), new Stack<T>());
        }

        /// <summary>
        /// Provides a mechanism to recurse through the tree while providing
        /// access to the current item's ancestry
        /// </summary>
        /// <param name="action">The action to yield to for each branch, providing the
        /// current item, and its ancestry.</param>
        public void ForEachRecursive(Action<Tree<T>, Stack<T>> action)
        {
            ForEachRecursive(action, new Stack<T>());
        }

        private void ForEachRecursive(Action<Tree<T>, Stack<T>> action, Stack<T> ancestry)
        {
            action(this, ancestry);
            ancestry.Push(Value);
            _branches.ForEach(branch => branch.ForEachRecursive(action, ancestry));
            ancestry.Pop();
        }
    }
}